/**
 * 绘图工具
 */
const LEFT_MOUSE_CLICK = Cesium.ScreenSpaceEventType.LEFT_CLICK //鼠标左键点击事件
const RIGHT_MOUSE_CLICK = Cesium.ScreenSpaceEventType.RIGHT_CLICK //鼠标右键点击事件
const MOUSE_MOVE = Cesium.ScreenSpaceEventType.MOUSE_MOVE //鼠标移动事件

class DrawGraphics {
  //properties
  _viewer = undefined
  _drawHandlerPools = undefined //绘图工具事件句柄存储池-{key-value形式}
  _entityCollector = Object.create(null) //实体收集器对象
  _graphicTypes = ['point', 'polyline', 'polygon', 'label'] //图形类型列表
  _tempCollector = new Cesium.EntityCollection() //初始化临时的实体收集器
  /**
   * 构造器
   * @param {*} options
   */
  constructor(options = {}) {
    this._initProperties_(options)
  }

  _initProperties_(options = {}) {
    const { viewer } = options
    this._viewer = viewer
    this._drawHandlerPools = Object.create(null) //存储handler事件处理对象
    //初始化时,根据图形类型创建实体收集器集合
    for (let i = 0; i < this._graphicTypes.length; i++) {
      const type = this._graphicTypes[i]
      this._entityCollector[type] = new Cesium.EntityCollection()
    }
  }

  /**
   * 绘图方法
   * @param {*} type 绘图类型-可选参数值-{point,polyline,polygon,label}
   */
  // drawGraphics(type = 'point') {
  //   switch (type.trim().toLowerCase()) {
  //     case 'point': {
  //       this.drawPoint()
  //       break
  //     }
  //     case 'polyline': {
  //       break
  //     }
  //     case 'polygon': {
  //       break
  //     }
  //     case 'label': {
  //       break
  //     }
  //   }
  // }

  /**
   * 创建uuid
   * Creates a Globally unique identifier (GUID) string. A GUID is 128 bits long, and can guarantee uniqueness across space and time.
   */
  getUUID() {
    return Cesium.createGuid()
  }

  /**
   * 清空临时实体收集器中的Entity
   */
  clearTempCollector() {
    if (this._tempCollector.values.length === 0) return
    const { _viewer: viewer } = this
    for (let i = 0; i < this._tempCollector.values.length; i++) {
      const entity = this._tempCollector.values[i]
      viewer.entities.remove(entity)
    }
    //清空临时实体收集器
    this._tempCollector.removeAll()
  }

  /**
   * 创建基本图形-Point
   */
  createPoint(options = {}) {
    const { _viewer: viewer } = this
    const {
      id = this.getUUID(),
      name = 'point',
      cartesian3,
      pixelSize = 5,
      heightReference = Cesium.HeightReference.NONE,
      color = Cesium.Color.RED,
      outlineWidth = 0,
      outlineColor = Cesium.Color.BLACK,
      disableDepthTestDistance = Number.POSITIVE_INFINITY,
    } = options
    const point = viewer.entities.add({
      id: id,
      name: name,
      show: true,
      position: cartesian3,
      point: {
        pixelSize: pixelSize,
        heightReference: heightReference,
        color: color,
        outlineWidth: outlineWidth,
        outlineColor: outlineColor,
        disableDepthTestDistance: disableDepthTestDistance,
      },
    })
    return point
  }

  /**
   * 绘制线段-[两个端点]
   */
  createLineSegment(startPosition, endPosition, options = {}) {
    const { _viewer: viewer } = this
    const {
      id = this.getUUID(),
      name = 'point',
      color = Cesium.Color.RED,
      width = 1,
      clampToGround = true,
      classificationType = Cesium.ClassificationType.BOTH, //Both terrain and 3D Tiles will be classified
    } = options //options解构
    const lineSegment = viewer.entities.add({
      id: id,
      name: name,
      show: true,
      polyline: {
        //线段
        positions: [startPosition, endPosition], //坐标点数组
        width: width, //线宽
        material: color,
        clampToGround: clampToGround, //是否贴地
        classificationType: classificationType, //贴地类型
      },
    })
    return lineSegment
  }

  /**
   * 绘制polyline线段
   * @param {*} options 配置项
   */
  createPolyline(options = {}) {
    const { _viewer: viewer } = this
    const {
      id = this.getUUID(),
      name = 'point',
      color = Cesium.Color.GREEN,
      positions = [],
      width = 3,
      clampToGround = true,
      classificationType = Cesium.ClassificationType.BOTH, //Both terrain and 3D Tiles will be classified
    } = options //options解构
    const polyLine = viewer.entities.add({
      id: id,
      name: name,
      show: true,
      polyline: {
        //线段
        positions: positions, //坐标点数组
        width: width, //线宽
        material: color,
        clampToGround: clampToGround, //是否贴地
        classificationType: classificationType, //贴地类型
      },
    })
    return polyLine
  }

  /**
   * 绘制polyline线段
   * @param {*} options 配置项
   */
  createPolylineByCallBackProperty(options = {}) {
    const { _viewer: viewer } = this
    return viewer.entities.add(options)
  }

  /**
   * 绘制Polygon多边形
   * @param {*} options 配置项
   */
  createPolygonByCallBackProperty(options = {}) {
    const { _viewer: viewer } = this
    return viewer.entities.add(options)
  }

  /**
   * 绘制Label标签
   * @param {*} options
   */
  createLabelByCallBackProperty(options = {}) {
    const { _viewer: viewer } = this
    return viewer.entities.add(options)
  }

  /**
   * 绘制点
   */
  drawPoint(type = `point`) {
    const self = this
    const { _viewer: viewer } = this
    //创建事件处理对象
    const handler_start = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    const handler_end = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    //绘制事件监听
    handler_start.setInputAction(function (event) {
      console.warn(`注册${type}绘制事件`)
      const { position: cartesian2_pos } = event //解构坐标点位
      //获取ray射线对象
      const ray = viewer.camera.getPickRay(cartesian2_pos)
      //窗口坐标转世界坐标
      const cartesian3_pos = viewer.scene.globe.pick(ray, viewer.scene)
      const point = self.createPoint({
        cartesian3: cartesian3_pos, //点位坐标值
      }) //绘制点
      //保存当前临时点位到实体收集器中
      self._entityCollector[type].add(point)
      console.log(self._entityCollector[type])
    }, LEFT_MOUSE_CLICK)

    //注销绘制事件监听
    handler_end.setInputAction(function (event) {
      console.warn(`移除${type}绘制事件`)
      handler_start.removeInputAction(LEFT_MOUSE_CLICK)
      handler_end.removeInputAction(RIGHT_MOUSE_CLICK)
    }, RIGHT_MOUSE_CLICK)
  }

  /**
   * 通过更新坐标点位的方式绘制polyline
   * @param {*} type
   */
  drawPolylineByUpdaatePositions(type = 'polyline') {
    const self = this
    const { _viewer: viewer } = this
    //存储临时坐标
    const linePositions = new Array()
    //polyline参数配置
    const polylineOptions = {
      id: this.getUUID(),
      name: 'polyline',
      show: true,
      polyline: {
        //线段
        positions: new Cesium.CallbackProperty(() => {
          return linePositions
        }, false), //坐标点数组,
        width: 3, //线宽
        material: Cesium.Color.GREEN,
        clampToGround: true, //是否贴地
        classificationType: Cesium.ClassificationType.BOTH, //Both terrain and 3D Tiles will be classified, //贴地类型
      },
    }
    //polyline对象
    const polyline_final = this.createPolylineByCallBackProperty(
      polylineOptions
    )
    //创建事件处理对象
    const handler_start = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标左键点击
    const handler_move = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标移动事件
    const handler_end = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标右键点击
    // 绘制事件监听
    handler_start.setInputAction(function (event) {
      console.warn(`注册${type}绘制事件`)
      const { position: cartesian2_pos } = event //解构坐标点位
      //获取ray射线对象
      const ray = viewer.camera.getPickRay(cartesian2_pos)
      //窗口坐标转世界坐标
      const cartesian3_pos = viewer.scene.globe.pick(ray, viewer.scene)
      //更新polyline的坐标参数
      polyline_final.polyline.positions = new Cesium.CallbackProperty(() => {
        return linePositions.concat(...[cartesian3_pos])
      }, false)
      //记录坐标点
      linePositions.push(cartesian3_pos)
    }, LEFT_MOUSE_CLICK)
    //注册鼠标移动事件监听
    handler_move.setInputAction(function (event) {
      // console.log(event);
      //当数组中长度大于1才执行
      // const length = linePositions.length; //记录当前数组长度
      // if(length>1){
      //     console.log(`自动绘制下一个点`);
      // }
    }, MOUSE_MOVE)

    //注销绘制事件监听
    handler_end.setInputAction(function (event) {
      console.warn(`移除${type}绘制事件`)
      handler_start.removeInputAction(LEFT_MOUSE_CLICK)
      handler_move.removeInputAction(MOUSE_MOVE)
      handler_end.removeInputAction(RIGHT_MOUSE_CLICK)
    }, RIGHT_MOUSE_CLICK)
  }

  /**
   * 绘制polyline
   */
  drawPolyline(type = 'polyline') {
    const self = this
    const { _viewer: viewer } = this
    //存储临时坐标
    const linePositions = new Array()
    //创建事件处理对象
    const handler_start = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标左键点击
    const handler_move = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标移动事件
    const handler_end = new Cesium.ScreenSpaceEventHandler(viewer.canvas) //鼠标右键点击
    //绘制事件监听
    handler_start.setInputAction(function (event) {
      console.warn(`注册${type}绘制事件`)
      const { position: cartesian2_pos } = event //解构坐标点位
      //获取ray射线对象
      const ray = viewer.camera.getPickRay(cartesian2_pos)
      //窗口坐标转世界坐标
      const cartesian3_pos = viewer.scene.globe.pick(ray, viewer.scene)
      //记录坐标点
      linePositions.push(cartesian3_pos)
      console.log(`当前坐标点数-${linePositions}`)
      //获取数组长度
      const length = linePositions.length
      //绘制点
      const point = self.createPoint(type, {
        cartesian3: linePositions[length - 1], //点位坐标值
      })
      self._tempCollector.add(point) //存放到临时实体收集器中
      //判断数组长度-绘制线
      if (linePositions.length > 1) {
        console.log('画线')
        const lineSegment = self.createLineSegment(
          linePositions[length - 2],
          linePositions[length - 1]
        )
        self._tempCollector.add(lineSegment) //存放到临时实体收集器中
      }
    }, LEFT_MOUSE_CLICK)
    //注册鼠标移动事件监听
    handler_move.setInputAction(function (event) {
      // console.log(event);
      //当数组中长度大于1才执行
      // const length = linePositions.length; //记录当前数组长度
      // if(length>1){
      //     console.log(`自动绘制下一个点`);
      // }
    }, MOUSE_MOVE)

    //注销绘制事件监听
    handler_end.setInputAction(function (event) {
      console.warn(`移除${type}绘制事件`)
      handler_start.removeInputAction(LEFT_MOUSE_CLICK)
      handler_move.removeInputAction(MOUSE_MOVE)
      handler_end.removeInputAction(RIGHT_MOUSE_CLICK)
      //移除临时线段
      self.clearTempCollector()
      console.log(self._tempCollector)
      //绘制polyline
      const polyline = self.createPolyline('polyline', {
        positions: linePositions,
      })
      this._entityCollector[collectorType].add(polyline) //记录当前polyline实体
    }, RIGHT_MOUSE_CLICK)
  }

  /**
   * 绘制polygon-多边形
   * @param {*} type
   */
  drawPolygonByUpdaatePositions(type = 'polygon') {
    const options = {
      id: this.getUUID(),
      name: 'polygon',
      show: true,
      polygon: {
        hierarchy: new Cesium.CallbackProperty(() => {
          return new Cesium.PolygonHierarchy([])
        }, false),
        height: 0,
        heightReference: Cesium.HeightReference.NONE,
        fill: true,
        material: Cesium.Color.RED.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 1.0,
        classificationType: Cesium.ClassificationType.BOTH,
      },
      properties:{
        positions:[],
      }
    }
    const linePositions = new Array() //顶点数组
    //创建多边形
    const polygonFinal = this.createPolygonByCallBackProperty(options) //创建一个多边形对象
    console.log(polygonFinal)
    //对象解构
    const { _viewer: viewer } = this
    //创建事件处理句柄
    const handler_start = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    const handler_end = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    //注册绘制事件
    handler_start.setInputAction(function (event) {
      console.warn(`注册${type}绘制事件`)
      const { position: cartesian2_pos } = event //解构坐标点位
      //获取ray射线对象
      const ray = viewer.camera.getPickRay(cartesian2_pos)
      //窗口坐标转世界坐标
      const cartesian3_pos = viewer.scene.globe.pick(ray, viewer.scene)
      //更新polyline的坐标参数
      polygonFinal.polygon.hierarchy = new Cesium.CallbackProperty(() => {
        return new Cesium.PolygonHierarchy(
          linePositions.concat(...[cartesian3_pos])
        )
      }, false)
      //记录坐标点
      linePositions.push(cartesian3_pos)
      //更新polygon属性
      polygonFinal.properties = {
        'positions':linePositions
      };
    }, LEFT_MOUSE_CLICK)
    //注销绘制事件
    handler_end.setInputAction(function () {
      console.warn(`移除${type}绘制事件`)
      handler_start.removeInputAction(LEFT_MOUSE_CLICK)
      handler_end.removeInputAction(RIGHT_MOUSE_CLICK)
    }, RIGHT_MOUSE_CLICK)
  }

  /**
   * 绘制Label标签
   * @param {*} type
   */
  drawLabelByUpdatePosition(type = 'label') {
    const self = this;
    //创建label标签
    const options = {
      id: this.getUUID,
      name: 'label',
      position: new Cesium.CallbackProperty(function () {
        return undefined
      }, false),
      label: {
        text: new Cesium.CallbackProperty(function () {
          return ''
        }, false),
      },
    }
    const label_Final = this.createLabelByCallBackProperty(options)
    const { _viewer: viewer } = this //对象解构
    //定义事件句柄
    const handler_start = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    const handler_end = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    //注册点击事件
    handler_start.setInputAction(function (event) {
      //获取世界坐标点位
      const { position: cartesian2_pos } = event //解构坐标点位
      console.log(cartesian2_pos)
      //获取ray射线对象
      const ray = viewer.camera.getPickRay(cartesian2_pos)
      //窗口坐标转世界坐标
      const cartesian3_pos = viewer.scene.globe.pick(ray, viewer.scene)
      label_Final.position = new Cesium.CallbackProperty(function () {
        return cartesian3_pos
      }, false)
      self.getLabelText(cartesian2_pos.y + 8, cartesian2_pos.x + 8, function (text) {
        label_Final.label.text = new Cesium.CallbackProperty(function () {
          return text
        }, false)
      })
    }, LEFT_MOUSE_CLICK)
    //取消点击事件
    handler_end.setInputAction(function () {
      handler_start.removeInputAction(LEFT_MOUSE_CLICK)
      handler_end.removeInputAction(RIGHT_MOUSE_CLICK)
    }, RIGHT_MOUSE_CLICK)
  }
  /**
   * 获取label标签内容
   */
  getLabelText(x = 110, y = 50, callback = (x) => x) {
    const div = document.createElement('div')
    //设置样式
    div.className = 'label_pop'
    div.style.padding = `15px 10px`
    div.style.position = 'absolute'
    div.style.width = `250px`
    div.style.top = `${x}px`
    div.style.left = `${y}px`
    div.style.color = `#fff`
    div.style.border = `1px solid rgba(18, 107, 223, 0.692)`
    div.style.backgroundColor = `rgba(58, 77, 109, .8)`
    div.style.boxShadow = ` 0 4px 15px 1px #02213bb3`
    div.style.zIndex = '10'
    //添加文档内容
    div.innerHTML = `
      <p class="title">请输入标签内容：</p>
      <hr style='margin:5px 0px'/>
      <input id='input_dom' style='margin:8px;width:95%;' type="text" value="" placeholder='标签文本'/>
      <div style='display:flex;flex-direcction:row;justify-content:space-around;align-items:center'>
          <button id='btn_ok'>确认</button><button id='btn_cancel'>取消</button>
      </div>
    `
    //添加点击事件
    //确认点击
    div.querySelector('#btn_ok').addEventListener('click', function () {
      const inputVal = div.querySelector('#input_dom').value
      callback(inputVal)
      div.style.display = 'none';
    })
    //取消事件
    div.querySelector('#btn_cancel').addEventListener('click', function () {
      callback('')
      div.style.display = 'none';
    })
    //添加div到document文档容器中
    document.body.appendChild(div)
  }


  /**
   * 开启编辑模式
   */
  startEdit(){
    const { _viewer:viewer } = this;
    const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    //注册点击事件
    handler.setInputAction(function(event){
       //获取临要素
       const pickedFeature = viewer.scene.pick(event.position);
       console.log(pickedFeature)
       if(pickedFeature.id){
          const entity = pickedFeature.id;
          //根据name字段判断类型
          switch(entity.name){
            case "point":{

              break;
            }
            case "polyline":{

              break;
            }
            case "polygon":{
              //修改material材质颜色
              entity.polygon.material = Cesium.Color.ORANGE.withAlpha(0.3);
              //获取顶点坐标
              const positions = entity.properties.positions;
              console.log(positions);
              //根据positions绘制临时点-赋予唯一id值

              //移动点时,同步更新polygon的坐标串
              
              break;
            }
            case "label":{

              break;
            }
          }
       }

    },LEFT_MOUSE_CLICK);
  }
}
